#include "stdafx.h"
#include <string.h>
#include <vector>
#include <io.h>
#include <algorithm>
#include <ctype.h>
#include <direct.h>
#include "Encrypt.h"

using namespace std;

bool s_bEncryptionKeyIsValid = false;

unsigned int s_uEncryptedPvrKeyParts[4] = { 0, 0, 0, 0 };
unsigned int s_uEncryptionKey[1024];
const char CCZv_sig[] = { 'C', 'C', 'Z', 'v' };
const char CCZp_sig[] = { 'C', 'C', 'Z', 'p' };

void decodeEncodedPvr(unsigned int *data, ssize_t len)
{
	const int enclen = 1024;
	const int securelen = 512;
	const int distance = 64;

	// create long key
	if (!s_bEncryptionKeyIsValid)
	{
		unsigned int y, p, e;
		unsigned int rounds = 6;
		unsigned int sum = 0;
		unsigned int z = s_uEncryptionKey[enclen - 1];

		do
		{
#define DELTA 0x9e3779b9
#define MX (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (s_uEncryptedPvrKeyParts[(p&3)^e] ^ z)))

			sum += DELTA;
			e = (sum >> 2) & 3;

			for (p = 0; p < enclen - 1; p++)
			{
				y = s_uEncryptionKey[p + 1];
				z = s_uEncryptionKey[p] += MX;
			}

			y = s_uEncryptionKey[0];
			z = s_uEncryptionKey[enclen - 1] += MX;

		} while (--rounds);

		s_bEncryptionKeyIsValid = true;
	}

	int b = 0;
	int i = 0;

	// encrypt first part completely
	for (; i < len && i < securelen; i++) {
		data[i] ^= s_uEncryptionKey[b++];

		if (b >= enclen)
		{
			b = 0;
		}
	}

	// encrypt second section partially
	for (; i < len; i += distance)
	{
		data[i] ^= s_uEncryptionKey[b++];
		if (b >= enclen)
		{
			b = 0;
		}
	}
}

bool isCCZVBuffer(unsigned char *buff, int buffLen) {
	if (buffLen > sizeof(CCZHeader) && memcmp(buff, CCZv_sig, sizeof(CCZv_sig)) == 0) {
		return true;
	}
	return false;
}

bool isCCZPBuffer(unsigned char *buff, int buffLen) {
	if (buffLen > sizeof(CCZHeader) && memcmp(buff, CCZp_sig, sizeof(CCZp_sig)) == 0) {
		return true;
	}
	return false;
}

int calcChecksumPvr(const unsigned int *data, ssize_t len) {
	unsigned int cs = 0;
	const int cslen = 128;

	len = (len < cslen) ? len : cslen;
	for (int i = 0; i < len; i++) {
		cs = cs ^ data[i];
	}
	return cs;
}

